﻿
using System;
using Game2DFramework.Drawing;
using Game2DFramework.Scripting;
using Game2DFramework.States;
using Game2DFramework.States.Transitions;
using MechGame.Game.Leveling;
using MechGame.Game.Overlay;
using MechGame.Game.Particles;
using MechGame.Game.PlayerRobot;
using MechGame.GameMenu;
using MechGame.Utility;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace MechGame.Game
{
    class InGameState : InitializableState
    {
        public static readonly Type Id = typeof (InGameState);

        private const float TransitDuration = 1.0f;

        private ExplosionManager _explosionManager;
        private ProjectileManager _projectileManager;
        private float _currentAlpha;
        private LevelChangeInformation _currentChange;
        private Level _level;
        private Player _player;
        private GameCursor _cursor;
        private Hud _hud;
        private Dialog _dialog;
        private CurrentGameState _state;
        private Menu _pauseMenu;
        private StateChangeInformation _stateChangeInformation;

        protected override void OnInitialize(object enterInformation)
        {
            _explosionManager = Game.RegisterGlobalObject("ExplosionManager", new ExplosionManager(Game));
            _projectileManager = Game.RegisterGlobalObject("ProjectileManager", new ProjectileManager(Game));
            _player = Game.RegisterGlobalObject("Player",  new Player(Game));
            _cursor = new GameCursor(Game);
            _dialog = new Dialog(Game, Game.Content.Load<Texture2D>("Textures/panel"), null,
                                       Game.Content.Load<SpriteFont>("Fonts/DialogFont"));
            _pauseMenu = new Menu(Game);
            _pauseMenu.AppendMenuItem(new MenuItem("Resume", () => _pauseMenu.Hide()));
            _pauseMenu.AppendMenuItem(new MenuItem("Quit to Mainmenu", OnQuitToMainMenu));
            _pauseMenu.AppendMenuItem(new MenuItem("Quit to Desktop", () => {}));
            _hud = new Hud(Game);
            _state = CurrentGameState.Normal;
            Game.ScriptRunner.Configure(new ScriptRunnerParameters { Dialog = _dialog });
        }

        private void OnQuitToMainMenu()
        {
            _stateChangeInformation = StateChangeInformation.StateChange(MainMenuState.Id, typeof (BlendTransition));
        }

        protected override void OnEntered(object enterInformation)
        {
            StartTransitToLevel(LevelChangeInformation.FromSavePoint("Levels/level1"));
            Mouse.SetPosition(Game.ScreenWidth / 2, Game.ScreenHeight / 2);
        }

        public override void OnLeave()
        {
        }

        public override StateChangeInformation OnUpdate(float elapsed)
        {
            _stateChangeInformation = StateChangeInformation.Empty;

            switch (_state)
            {
                case CurrentGameState.Normal:
                    UpdateNormal(elapsed);
                    break;
                case CurrentGameState.Paused:
                    UpdatePaused(elapsed);
                    break;
                case CurrentGameState.LeaveLevel:
                    UpdateLeaveLevel(elapsed);
                    break;
                case CurrentGameState.EnterLevel:
                    UpdateEnterLevel(elapsed);
                    break;
            }

            return _stateChangeInformation;
        }

        private void UpdatePaused(float elapsed)
        {
            _cursor.Update();
            _pauseMenu.Update(elapsed);

            if (_pauseMenu.State == MenuState.Hidden) _state = CurrentGameState.Normal;

            if (_pauseMenu.State == MenuState.Shown & Game.Keyboard.IsKeyDownOnce(Keys.Escape))
            {
                _pauseMenu.Hide();
            }
        }

        private void UpdateEnterLevel(float elapsedTime)
        {
            _currentAlpha -= elapsedTime*TransitDuration;
            if (_currentAlpha <= 0)
            {
                _currentAlpha = 0;
                _state = CurrentGameState.Normal;
                _player.LockControl = false;
            }
        }

        private void UpdateLeaveLevel(float elapsed)
        {
            _currentAlpha += elapsed * TransitDuration;
            if (_currentAlpha >= 1)
            {
                PrepareForCurrentLevel();
                _state = CurrentGameState.EnterLevel;
                _currentAlpha = 1;
            }
        }

        private void PrepareForCurrentLevel()
        {
            var levelWasNull = _level == null;
            _level = new Level(Game, _currentChange.NewLevel);

            if (levelWasNull)
            {
                Game.RegisterGlobalObject("Level", _level);
            }
            else
            {
                Game.ReplaceGlobalObject("Level", _level);
            }

            Game.Camera.SetFollowWithBoundaryBehavior(_level.WorldBounds, _player);
            switch (_currentChange.From)
            {
                case StartUpFrom.SavePoint:
                    _level.StartPlayerInCatchedMode(_player);
                    break;
                case StartUpFrom.Door:
                    _player.Position = _currentChange.Position;
                    break;
            }
        }

        private void UpdateNormal(float elapsed)
        {
            var levelChange = _level.Update(elapsed);
            _explosionManager.Update(elapsed);
            _projectileManager.Update(elapsed);
            _dialog.Update(elapsed);
            _player.Update(elapsed);
            _cursor.Update();
            _hud.Update();
            _pauseMenu.Update(elapsed);

            if (Game.Keyboard.IsKeyDownOnce(Keys.Escape) && _pauseMenu.State == MenuState.Hidden) 
            {
                _pauseMenu.Show();
                _state = CurrentGameState.Paused;
            }

            if (_level.State == LevelState.PlayerInSaveBase && Game.Keyboard.IsKeyDownOnce(Keys.Space)) _level.LeaveSaveBase();
            if (!string.IsNullOrEmpty(levelChange.NewLevel))
            {
                StartTransitToLevel(levelChange);
            }
        }

        private void StartTransitToLevel(LevelChangeInformation changeInformation)
        {
            _currentChange = changeInformation;
            _state = CurrentGameState.LeaveLevel;
            _currentAlpha = _level == null ? 1 : 0;
        }

        public override void OnDraw(float elapsedTime)
        {
            Game.GraphicsDevice.Clear(Color.Black);

            if (_level != null)
            {
                _level.Draw();
                _projectileManager.Draw();
                _explosionManager.Draw();
            }

            Game.ActivateDefaultView();

            _hud.Draw();
            _dialog.Draw();
            _pauseMenu.Draw();
            _cursor.Draw();

            if (_state != CurrentGameState.Normal)
            {
                Game.ShapeRenderer.DrawFilledRectangle(0,0, Game.ScreenWidth, Game.ScreenHeight, Color.Black * _currentAlpha);
            }
        }
    }
}
